from prg.common.object_message import MessageBase
from prg.link_info import LinkItem
from prg.entity.authority_entity import *
from prg.common.common_base import CommonBase
from prg.command_info import CommandInfo
from prg.entity.arg_entity import ArgBase
from prg.bll.authority_bll import AuthorityBll
from prg.proc.link_thread import ConnectClient
from prg.bll.config_bll import ConfigBll
from prg.entity.public_entity import PublicEntity
from threading import Lock


class HandleThread(MessageBase):

    def __init__(self):
        super().__init__(name="handle")
        self.inner_lock = Lock()
        self.public_item = PublicEntity.instance()
        self.config = ConfigBll.instance().get_base_config()
        self.user = AuthorityBll.instance()
        self.handle_queue = self.public_item.handle
        self.command_queue = self.public_item.command
        self.addr = self.public_item.addr

    def get_queue(self):
        return self.handle_queue

    def add(self, handle):
        self.handle_queue.put(handle)

    def create_send_cmd(self, addr, cmd, arg_dict):
        user_inf = addr.get_user_info()
        arg = ArgBase()
        arg.sign = user_inf.password
        arg.arg_dict = arg_dict
        arg_str = CommonBase.aes_encryption_json(key=user_inf.aes, entity=arg)
        cmd_item = CommandInfo(socket_item=addr.get_socket(), command=cmd, name=addr.get_name(), arg=arg_str)
        self.command_queue.put(cmd_item)

    def callback_login(self, register_item):
        arg_dict = dict()
        arg_dict["verification"] = register_item.get_verification()
        arg_dict["sign"] = register_item.get_sign()
        arg_dict["name"] = register_item.get_name()
        arg_dict["link_id"] = register_item.get_link_id()
        self.create_send_cmd(addr=register_item, cmd="info", arg_dict=arg_dict)

    def check_user(self, header_inf):
        user_inf = self.user.get_user(header_inf.name)
        header = header_inf.get_head_entity(key=user_inf.aes)
        assert user_inf.password == header.arg.sign
        return user_inf

    def get_link_id(self):
        self.inner_lock.acquire()
        self.public_item.client_number += 1
        link_id = self.public_item.server_id + self.public_item.client_number
        self.inner_lock.release()
        return link_id

    def run_handle(self):
        header_inf = self.handle_queue.get()
        self.handle_queue.task_done()
        addr_name = header_inf.name
        if "login" == header_inf.get_command():
            user_inf = self.check_user(header_inf=header_inf)
            reg_item = LinkItem(addr_name, header_inf.get_client_socket())
            reg_item.set_user_info(user_inf)
            reg_item.set_timeout(self.config.timeout.user)
            reg_item.set_link_id(link_id=self.get_link_id())
            log_inf = (reg_item.get_link_id(), addr_name, reg_item.get_sign(), reg_item.get_verification())
            print("login -> %s %s sign: %s, verification: %s" % log_inf)
            self.addr[addr_name] = reg_item
            self.callback_login(reg_item)
        elif "register" == header_inf.get_command():
            header = header_inf.get_head_entity()
            user_inf = AuthorityItem()
            user_inf.name = addr_name
            user_inf.aes = header.arg.arg_dict["aes"]
            reg_item = LinkItem(addr_name, header_inf.get_client_socket())
            reg_item.set_user_info(user_inf)
            reg_item.set_timeout(self.config.timeout.guest)
            reg_item.set_link_id(link_id=self.get_link_id())
            reg_inf = (reg_item.get_link_id(), addr_name, reg_item.get_sign(), reg_item.get_verification())
            print("register -> %s %s sign: %s, verification: %s" % reg_inf)
            self.addr[addr_name] = reg_item
            self.callback_login(reg_item)
        elif "to" == header_inf.get_command():
            assert addr_name in self.addr
            from_item = self.addr[addr_name]
            user_inf = from_item.get_user_info()
            header = header_inf.get_head_entity(key=user_inf.aes)
            to_name = header.arg.arg_dict["to"]
            local_port = header.arg.arg_dict["local"]
            task_id = header.arg.arg_dict["task"]
            assert to_name in self.addr
            to_item = self.addr[to_name]
            head_verify = header.arg.arg_dict["verification"]
            verification_code = CommonBase.aes_decrypt(key=to_item.get_sign(), data=head_verify)
            print("link %s -> %s, verification: %s" % (addr_name, to_name, verification_code))
            assert verification_code == from_item.get_verification()
            print("link %s -> %s verify ok" % (addr_name, to_name))
            conn_item = ConnectClient(from_addr=addr_name, to_addr=to_name, local_port=local_port, task_id=task_id)
            conn_item.start()

    def entry(self):
        while self.is_run():
            try:
                if not self.handle_queue.empty():
                    print("queue length %s" % str(self.handle_queue.qsize()))
                    self.run_handle()
            except Exception as e:
                print("handle error: %s" % e)

